package com.hyper_yang._05_juc.chap01;

//封装资源类：卖票的类
class Ticket {
    private int number = 20; //票数

    //卖票
/*    public synchronized void sale() { //加锁   给方法增加加锁标志： ACC_SYNCHRONIZED   不运行并发调用。线程同步(串行)调用
        //票不能出现负数  即：不能超卖
        if (number <= 0) {
            System.out.println(" 售罄 ");
            return;
        }

        System.out.println(Thread.currentThread().getName() + " 开始买票-剩余 = " + number);
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 卖掉一张票，然后剩余 = " + --number); // ++ -- 不是原子性，不安全
    }*/

    public void sale() { //加锁   给方法增加加锁标志： ACC_SYNCHRONIZED   不运行并发调用。线程同步(串行)调用
        synchronized (this){ //  JVM通过monitorenter指令加锁
            //票不能出现负数  即：不能超卖
            if (number <= 0) {
                System.out.println(" 售罄 ");
                return;
            }

            System.out.println(Thread.currentThread().getName() + " 开始买票-剩余 = " + number);
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 卖掉一张票，然后剩余 = " + --number); // ++ -- 不是原子性，不安全
        }//  JVM通过monitorexit指令解锁 （一个monitorenter对应两个monitorexit（一个正常解锁，一个异常时解锁））
    }
}

/**
 * 多线程编程模板：
 * 模板1：
 * 1.高内聚、低耦合
 * 2、线程 操作 资源类
 * 案例：卖票程序，三个窗口(线程)来卖20张票。
 */
public class SaleTicket {
    public static void main(String[] args) {
        //创建资源列对象
        Ticket ticket = new Ticket();

        //卖票窗口A
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "A").start();

        //卖票窗口B
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "B").start();

        //卖票窗口C
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                ticket.sale(); //操作
            }
        }, "C").start();
    }
}
